package helper;

import bill.WithdrawalsBill;
import bill.WithdrawalsUserBill;
import com.google.gson.Gson;
import com.pingplusplus.Pingpp;
import com.pingplusplus.exception.*;
import com.pingplusplus.model.Charge;
import com.pingplusplus.model.RedEnvelope;
import com.pingplusplus.model.Transfer;
import enums.OrderStatus;
import goods.Goods;
import models.merchant.MerchantAccount;
import models.weixin.WebUser;
import order.Order;
import order.OrderItem;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import play.Logger;
import play.mvc.Http;
import play.vfs.VirtualFile;
import product.Product;
import utils.DateUtil;

import java.math.BigDecimal;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Ping++ 支付支持.
 */
public class PingppHelper {

    private  static java.text.DecimalFormat   df   =new   java.text.DecimalFormat("#.00");


    static {
        Pingpp.apiKey = GlobalConfig.PINGPP_API_KEY;
    }


    /**
     * 企业红包 用于提现
     * @param withdrawalsBill
     * @return
     * @throws ChannelException
     * @throws APIException
     * @throws AuthenticationException
     * @throws InvalidRequestException
     * @throws APIConnectionException
     */
    public static Transfer transferForWxPub(WithdrawalsBill withdrawalsBill , WebUser webUser) throws ChannelException, APIException, AuthenticationException, InvalidRequestException, APIConnectionException {
        Map<String, Object> transferMap = new HashMap<String, Object>();
        transferMap.put("channel", "wx_pub");//此处 wx_pub 为公众平台的支付
        transferMap.put("order_no", withdrawalsBill.billCode);
        transferMap.put("amount", withdrawalsBill.amount);//订单总金额, 人民币单位：分（如订单总金额为 1 元，此处请填 100）
        transferMap.put("type", "b2c");
        transferMap.put("currency", "cny");
        transferMap.put("recipient", webUser.openId);//企业付款给指定用户的 open_id
        transferMap.put("description", "提现成功");
        Map<String, String> app = new HashMap<String, String>();
        Logger.info("withdrawalsBill.merchant.weixinData.pingppApiId :%s", withdrawalsBill.merchant.weixinData.pingppApiId);
        app.put("id", withdrawalsBill.merchant.weixinData.pingppApiId);
        transferMap.put("app", app);
        Map<String, Object> extra = new HashMap<String, Object>();
        extra.put("user_name", withdrawalsBill.merchant.name);
        extra.put("force_check", false);
        transferMap.put("extra", extra);
        return  Transfer.create(transferMap);
    }


    public static Charge chargeAlipayPC(Order order , String linkId) {

//        Logger.info("User From : %s | to Pay : %s" , order.webUser.weixinData.appId , order.webUser.weixinData.appId);
        if (order.status == OrderStatus.UNPAID) {
            Map<String, Object> chargeParams = new HashMap<>();
            chargeParams.put("order_no", order.orderNumber);
            chargeParams.put("amount", 1);
            Logger.info("LOG0181222: orderNumber:%s, amount:%s, cent:%s", order.orderNumber, order.paymentedAmount, order.paymentedAmount);
            Map<String, String> app = new HashMap<>();
            app.put("id",  order.webUser.weixinData.pingppApiId);
            chargeParams.put("app", app);
            chargeParams.put("channel", "alipay_pc_direct");
            chargeParams.put("currency", "cny");

            String remoteAddress = Http.Request.current().remoteAddress;
            if (remoteAddress == null || remoteAddress.length() > 15 || remoteAddress.contains(":")) {
                Logger.info("LOG02580: bad ip address:" + remoteAddress);
                remoteAddress = "127.0.0.1";
            }
            chargeParams.put("client_ip", remoteAddress);
            chargeParams.put("subject", StringUtils.isBlank(order.remark) ? "暂无" : order.remark);
            chargeParams.put("body", linkId);
            Map<String, String> extras = new HashMap<>();
            extras.put("success_url", "http://" + GlobalConfig.APPLICATION_BASE_DOMAIN + "/pay/" + order.orderNumber + "/succ");
            chargeParams.put("extra", extras);
            try {
                Logger.info("chargeParams :%s",chargeParams);
                return Charge.create(chargeParams);
            } catch (Exception e) {
                Logger.warn(e, "LOG01831: create charege failed! orderNumber:" + order.orderNumber);
            }
        } else {
            Logger.warn("LOG02440: orderNumber:%s 状态不是未支付, 实际状态是:%s", order.orderNumber, order.status);
        }
        return null;
    }



    public static Charge chargeAli_PC_direct (Order order , String subject) {
        Map<String, Object> chargeParams = new HashMap<>();
        chargeParams.put("order_no",  order.orderNumber);
        Double amount = Double.valueOf(df.format(order.paymentedAmount));
        chargeParams.put("amount", amount * 100);//订单总金额, 人民币单位：分（如订单总金额为 1 元，此处请填 100）
        Map<String, String> app = new HashMap<>();
        Logger.info("Ping++ ApiId : %s" , order.webUser.weixinData.pingppApiId);
        app.put("id", order.webUser.weixinData.pingppApiId);
        chargeParams.put("app", app);
        chargeParams.put("channel",  "alipay_pc_direct");
        chargeParams.put("currency", "cny");

        String remoteAddress = Http.Request.current().remoteAddress;
        if (remoteAddress == null || remoteAddress.length() > 15 || remoteAddress.contains(":")) {
            Logger.info("LOG02581: bad ip address:" + remoteAddress);
            remoteAddress = "127.0.0.1";
        }
        chargeParams.put("client_ip", remoteAddress);


        chargeParams.put("subject",  subject);
        chargeParams.put("body",  StringUtils.isBlank(order.remark) ? "暂无" : order.remark);
        Map<String, String> extra = new HashMap<>();
        extra.put("success_url", "http://www.ulmsale.net/pc/font/callback");
        chargeParams.put("extra", extra);
        try {
            Logger.info("Charge : %s" , new Gson().toJson(Charge.create(chargeParams)));
            return Charge.create(chargeParams);
        } catch (Exception e) {
            Logger.warn(e, "LOG01831: create charege failed! orderNumber:" + order.orderNumber);
        }
        return null;
    }

    public static Charge chargeWeixinGZ(Order order , String subject , WebUser webUser) {
        if (order.status == OrderStatus.UNPAID) {
            Map<String, Object> chargeParams = new HashMap<>();
            chargeParams.put("order_no", order.orderNumber);
//            String appId  = GlobalConfig.WEIXIN_APP_ID;
            Double amount = 0d;
//            if(appId.equals("wx5a5f34b7af97ac5e")) {
//                amount = 1d;
//            } else {
                amount = order.paymentedAmount * 100;
//            }
            chargeParams.put("amount", amount.intValue());
            Logger.info("LOG01812: orderNumber:%s, amount:%s, cent:%s", order.orderNumber, order.paymentedAmount, order.paymentedAmount);
            Map<String, String> app = new HashMap<>();
            app.put("id",  webUser.weixinData.pingppApiId);
            chargeParams.put("app", app);
            chargeParams.put("channel", "wx_pub");
            chargeParams.put("currency", "cny");

            String remoteAddress = Http.Request.current().remoteAddress;
            if (remoteAddress == null || remoteAddress.length() > 15 || remoteAddress.contains(":")) {
                Logger.info("LOG02580: bad ip address:" + remoteAddress);
                remoteAddress = "127.0.0.1";
            }
            chargeParams.put("client_ip", remoteAddress);
//            OrderItem orderItem = OrderItem.getByOrder(order);
//            Product product = Product.findById(Goods.separationId(orderItem.goods));
            chargeParams.put("subject", subject);
            chargeParams.put("body", StringUtils.isBlank(order.remark) ? "暂无" : order.remark);
            Map<String, String> extras = new HashMap<>();
//            WeixinUser wxUser = WeixinUser.findByUser(order.user);
            extras.put("open_id", webUser.openId);
            chargeParams.put("extra", extras);

            // 设置支付超时时间  默认 14分钟  跟检测订单时间错开
            Date afterDate = DateUtil.getAfterMinutes(order.createdAt , 14);
            Long timestamp = DateUtil.dateToTimestamp(afterDate);
            Logger.info("支付超时时间 : %s" , timestamp);
            chargeParams.put("time_expire" , timestamp);
            try {
                return Charge.create(chargeParams);
            } catch (Exception e) {
                Logger.warn(e, "LOG01831: create charege failed! orderNumber:" + order.orderNumber  + "  Error : %s" , e.getMessage());
            }
        } else {
            Logger.warn("LOG02440: orderNumber:%s 状态不是未支付, 实际状态是:%s", order.orderNumber, order.status);
        }
        return null;
    }


    /**
     * 创建 Charge (微信公众号)
     *
     * 创建 Charge 用户需要组装一个 map 对象作为参数传递给 Charge.create();
     * map 里面参数的具体说明请参考：https://www.pingxx.com/api#api-c-new
     * @return Charge
     */
    public static Charge createChargeByWeixinQr(Order order) {
        if(order == null || order.status == null || order.status != OrderStatus.UNPAID) {
            return null;
        }
        Charge charge = null;
        Map<String, Object> chargeMap = new HashMap<>();
        chargeMap.put("amount", order.paymentedAmount * 100);//订单总金额, 人民币单位：分（如订单总金额为 1 元，此处请填 100）
        chargeMap.put("currency", "cny");

        OrderItem orderItem = OrderItem.getByOrder(order);
        Product product = Product.findById(Goods.separationId(orderItem.goods));
        chargeMap.put("subject", product.name + "等");
        chargeMap.put("body", StringUtils.isBlank(order.remark) ? "暂无" : order.remark);


        chargeMap.put("order_no", order.orderNumber);// 推荐使用 8-20 位，要求数字或字母，不允许其他字符
        chargeMap.put("channel", "wx_pub_qr");// 支付使用的第三方支付渠道取值，请参考：https://www.pingxx.com/api#api-c-new
        chargeMap.put("client_ip", "127.0.0.1"); // 发起支付请求客户端的 IP 地址，格式为 IPV4，如: 127.0.0.1
        Map<String, String> app = new HashMap<>();
        app.put("id", order.merchant.weixinData.pingppApiId);
        chargeMap.put("app", app);

        Map<String, Object> extra = new HashMap<String, Object>();
        extra.put("product_id", order.orderNumber);
        chargeMap.put("extra", extra);
        try {
            //发起交易请求
            charge = Charge.create(chargeMap);
            // 传到客户端请先转成字符串 .toString(), 调该方法，会自动转成正确的 JSON 字符串
            String chargeString = charge.toString();
            System.out.println(chargeString);
        } catch (PingppException e) {
            e.printStackTrace();
        }
        return charge;
    }



    /**
     * 创建 Charge (微信公众号)
     *
     * 创建 Charge 用户需要组装一个 map 对象作为参数传递给 Charge.create();
     * map 里面参数的具体说明请参考：https://www.pingxx.com/api#api-c-new
     * @return Charge
     */
    public static Charge createScanCodePay(Order order , String payType) {
        Logger.info("createScanCodePay order : %s | payType : %s" , order , payType);
        if(order == null || order.status == null || order.status != OrderStatus.UNPAID) {
            return null;
        }
        Charge charge = null;
        Map<String, Object> chargeMap = new HashMap<>();
        Double amount = Double.valueOf(df.format(order.paymentedAmount));
        chargeMap.put("amount", amount * 100);//订单总金额, 人民币单位：分（如订单总金额为 1 元，此处请填 100）
        chargeMap.put("currency", "cny");

        OrderItem orderItem = OrderItem.getByOrder(order);
        //Product product = Product.findById(Goods.separationId(orderItem.goods));
        //chargeMap.put("subject", product.name + "等");
        chargeMap.put("subject", orderItem.goods.name + "等");
        chargeMap.put("body", StringUtils.isBlank(order.remark) ? "暂无" : order.remark);


        chargeMap.put("order_no", order.orderNumber);// 推荐使用 8-20 位，要求数字或字母，不允许其他字符
        chargeMap.put("channel", payType);// 支付使用的第三方支付渠道取值，请参考：https://www.pingxx.com/api#api-c-new
        chargeMap.put("client_ip", "127.0.0.1"); // 发起支付请求客户端的 IP 地址，格式为 IPV4，如: 127.0.0.1
        Map<String, String> app = new HashMap<>();
        //TOD 切换成商户的appid
        Logger.info("Appid : %s" , order.merchant.weixinData.pingppApiId);
        app.put("id", order.merchant.weixinData.pingppApiId);
        chargeMap.put("app", app);

        if("wx_pub_qr".equals(payType)) {
            Map<String, Object> extra = new HashMap<>();
            extra.put("product_id", order.orderNumber);
            chargeMap.put("extra", extra);
        }
        try {
            //发起交易请求
            charge = Charge.create(chargeMap);
            // 传到客户端请先转成字符串 .toString(), 调该方法，会自动转成正确的 JSON 字符串
            String chargeString = charge.toString();
            System.out.println(chargeString);
        } catch (PingppException e) {
            charge = null;
            Logger.info("Charge error : %s" , e.getMessage());
            e.printStackTrace();
        }
        return charge;
    }



    public static Charge chargeWeixinQR(Order order) {
        if (order.status == OrderStatus.UNPAID) {
            Map<String, Object> chargeParams = new HashMap<>();
            chargeParams.put("order_no", order.orderNumber);
            chargeParams.put("amount", 1);
            Logger.info("LOG01812: orderNumber:%s, amount:%s, cent:%s", order.orderNumber, order.paymentedAmount, order.paymentedAmount);
            Map<String, String> app = new HashMap<>();
            app.put("id", order.webUser.weixinData.pingppApiId);
            chargeParams.put("app", app);
            chargeParams.put("channel", "wx_pub_qr");
            chargeParams.put("currency", "cny");

            String remoteAddress = Http.Request.current().remoteAddress;
            if (remoteAddress == null || remoteAddress.length() > 15 || remoteAddress.contains(":")) {
                Logger.info("LOG02580: bad ip address:" + remoteAddress);
                remoteAddress = "127.0.0.1";
            }
            chargeParams.put("client_ip", remoteAddress);
            OrderItem orderItem = OrderItem.getByOrder(order);
            Product product = Product.findById(Goods.separationId(orderItem.goods));
            chargeParams.put("subject", product.name + "等");
            chargeParams.put("body", StringUtils.isBlank(order.remark) ? "暂无" : order.remark);
            Map<String, String> extras = new HashMap<>();
            extras.put("product_id", String.valueOf(product.id));
            extras.put("open_id" , order.webUser.openId);
            extras.put("goods_tag" , "暂无");
            extras.put("bank_type" , "中国工商银行");
            chargeParams.put("extra", extras);

            // 设置支付超时时间  默认 14分钟  跟检测订单时间错开
            Date afterDate = DateUtil.getAfterMinutes(order.createdAt , 14);
            Long timestamp = DateUtil.dateToTimestamp(afterDate);
            Logger.info("支付超时时间 : %s" , timestamp);
            chargeParams.put("time_expire" , timestamp);
            try {
                return Charge.create(chargeParams);
            } catch (Exception e) {
                Logger.warn(e, "LOG01831: create charege failed! orderNumber:" + order.orderNumber);
            }
        } else {
            Logger.warn("LOG02440: orderNumber:%s 状态不是未支付, 实际状态是:%s", order.orderNumber, order.status);
        }
        return null;
    }

    /**
     * 文字模板 ：  您参与 [subject] ，成功获得 [send_name] 赠送的红包 , [description]
     * 点击消息拆开红包即可获得现金
     * 点击后  [body]
     * @param subject  红包上面的名字
     * @param body
     * @param description
     * @param openId
     * @param orderNumber
     * @return
     */
    public static RedEnvelope createRejgbEnvelope(Double amount , String subject , String body , String description , String openId , String orderNumber) throws ChannelException, APIException, AuthenticationException, InvalidRequestException, APIConnectionException {

        Map<String, Object> redenvelope = new HashMap<String, Object>();
        redenvelope.put("order_no",  orderNumber);
        Map<String, String> app = new HashMap<String, String>();
        app.put("id", GlobalConfig.PINGPP_APP_ID);
        redenvelope.put("app", app);
        redenvelope.put("channel",  "wx_pub");//红包基于微信公众帐号，所以渠道是 wx_pub
        redenvelope.put("amount", amount * 100);//金额在 100-20000 之间
        redenvelope.put("currency", "cny");
        redenvelope.put("subject",  subject);
        redenvelope.put("body",  body);
        Map<String, String> extra = new HashMap<String, String>();
        extra.put("nick_name", "优粮城.日照社区家园");
        extra.put("send_name", "优粮城.日照社区家园");
        redenvelope.put("extra", extra);//extra 需填入的参数请参阅[API 文档]()
        redenvelope.put("recipient", openId);//指定用户的 open_id
        redenvelope.put("description", description);
            return RedEnvelope.create(redenvelope);
    }

    /**
     * 文字模板 ：  您参与 [subject] ，成功获得 [send_name] 赠送的红包 , [description]
     * 点击消息拆开红包即可获得现金
     * 点击后  [body]
     * @param openId
     * @param orderNumber
     * @return
     */
    public static RedEnvelope createRejgbEnvelope(BigDecimal amount , String nickName , String openId , String orderNumber){

        Map<String, Object> redenvelope = new HashMap<String, Object>();
        redenvelope.put("order_no",  orderNumber);
        Map<String, String> app = new HashMap<>();
        app.put("id", GlobalConfig.PINGPP_APP_ID);
        redenvelope.put("app", app);
        redenvelope.put("channel",  "wx_pub");//红包基于微信公众帐号，所以渠道是 wx_pub
        redenvelope.put("amount", amount.doubleValue() * 100);//金额在 100-20000 之间
        redenvelope.put("currency", "cny");
        redenvelope.put("subject",  "分享红包");
        redenvelope.put("body",  "分享红包");
        redenvelope.put("recipient", openId);//指定用户的 open_id
        Map<String, String> extra = new HashMap<String, String>();
//        extra.put("nick_name", nickName);
        extra.put("send_name", nickName);
        redenvelope.put("extra", extra);//extra 需填入的参数请参阅[API 文档]()
        redenvelope.put("description", "恭喜您获得 " + amount + "元分享红包");
        try {
            return RedEnvelope.create(redenvelope);
        } catch (Exception e) {
            Logger.warn(e, "LOG01833: create RedEnvelope failed! orderNumber:" + orderNumber  + " | Error : " + e.getMessage());
//            e.printStackTrace();
        }
        return null;
    }

    public static Charge chargeUpacpPc(Order order , String linkId) {
        if (order.status == OrderStatus.UNPAID) {
            Map<String, Object> chargeParams = new HashMap<>();
            chargeParams.put("order_no", order.orderNumber);
            chargeParams.put("amount", 1);
            Logger.info("LOG0181222: orderNumber:%s, amount:%s, cent:%s", order.orderNumber, order.paymentedAmount, order.paymentedAmount);
            Map<String, String> app = new HashMap<>();
            app.put("id",  GlobalConfig.PINGPP_APP_ID);
            chargeParams.put("app", app);
            chargeParams.put("channel", "upacp_pc");
            chargeParams.put("currency", "cny");

            String remoteAddress = Http.Request.current().remoteAddress;
            if (remoteAddress == null || remoteAddress.length() > 15 || remoteAddress.contains(":")) {
                Logger.info("LOG02580: bad ip address:" + remoteAddress);
                remoteAddress = "127.0.0.1";
            }
            chargeParams.put("client_ip", remoteAddress);
            chargeParams.put("subject", StringUtils.isBlank(order.remark) ? "暂无" : order.remark);
            chargeParams.put("body", linkId);
            Map<String, String> extras = new HashMap<>();
            extras.put("result_url", "http://" + GlobalConfig.APPLICATION_BASE_DOMAIN + "/pay/" + order.orderNumber + "/succ");
            chargeParams.put("extra", extras);
            try {
                Logger.info("chargeParams :%s",chargeParams);
                return Charge.create(chargeParams);
            } catch (Exception e) {
                Logger.warn(e, "LOG01831: create charege failed! orderNumber:" + order.orderNumber);
            }
        } else {
            Logger.warn("LOG02440: orderNumber:%s 状态不是未支付, 实际状态是:%s", order.orderNumber, order.status);
        }
        return null;
    }

    public static Transfer createTransfers(MerchantAccount merchantAccount , WebUser webUser) {
        Map<String, Object> transfer = new HashMap<String, Object>();
        transfer.put("amount", merchantAccount.account);
        transfer.put("currency", "cny");
        transfer.put("type",  "b2c");
        transfer.put("order_no",  merchantAccount.id.toString());
        transfer.put("channel",  "wx_pub");
        transfer.put("recipient", webUser.openId);
        transfer.put("description", "Your Description");
        Map<String, String> app = new HashMap<String, String>();
        app.put("id", "app_1Gqj58ynP0mHeX1q");
        transfer.put("app", app);
        Transfer t = null;
        try {
            t = Transfer.create(transfer);
        } catch (AuthenticationException e) {
            e.printStackTrace();
        } catch (InvalidRequestException e) {
            e.printStackTrace();
        } catch (APIConnectionException e) {
            e.printStackTrace();
        } catch (APIException e) {
            e.printStackTrace();
        } catch (ChannelException e) {
            e.printStackTrace();
        }
        return t;
    }


    /**
     * 获得Ping++公钥.
     */
    public static PublicKey getPubKey() throws Exception {
        VirtualFile pubFile = VirtualFile.fromRelativePath("/conf/pingpp.pub");

        String pubKey = pubFile.contentAsString();
        pubKey = pubKey.replaceAll("(-+BEGIN PUBLIC KEY-+\\r?\\n|-+END PUBLIC KEY-+\\r?\\n?)", "");

        byte[] keyBytes = Base64.decodeBase64(pubKey);

        // generate public key
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(spec);
    }

    /**
     * 用户提现
     * @param withdrawalsUserBill
     * @param webUser
     * @return
     * @throws ChannelException
     * @throws APIException
     * @throws AuthenticationException
     * @throws InvalidRequestException
     * @throws APIConnectionException
     */
    public static Transfer transferForWxUserPub(WithdrawalsUserBill withdrawalsUserBill , WebUser webUser) throws ChannelException, APIException, AuthenticationException, InvalidRequestException, APIConnectionException {
        Map<String, Object> transferMap = new HashMap<String, Object>();
        transferMap.put("channel", "wx_pub");//此处 wx_pub 为公众平台的支付
        transferMap.put("order_no", withdrawalsUserBill.billCode);
        transferMap.put("amount", withdrawalsUserBill.amount);//订单总金额, 人民币单位：分（如订单总金额为 1 元，此处请填 100）
        transferMap.put("type", "b2c");
        transferMap.put("currency", "cny");
        transferMap.put("recipient", webUser.openId);//企业付款给指定用户的 open_id
        transferMap.put("description", "提现成功");
        Map<String, String> app = new HashMap<String, String>();
        app.put("id", withdrawalsUserBill.webUser.weixinData.pingppApiId);
        transferMap.put("app", app);
        Map<String, Object> extra = new HashMap<String, Object>();
        extra.put("user_name", withdrawalsUserBill.webUser.nickName);
        extra.put("force_check", false);
        transferMap.put("extra", extra);
        return  Transfer.create(transferMap);
    }

}
